Átfogó útmutató a TypeScript middleware megértéséhez és implementálásához Express.js alkalmazásokban. Fedezze fel a fejlett típusmintákat a robusztus és karbantartható kódhoz.
TypeScript Middleware: Az Express Middleware Típusmintáinak Elsajátítása
Az Express.js, egy minimalista és rugalmas Node.js webalkalmazási keretrendszer, lehetővé teszi a fejlesztők számára, hogy robusztus és skálázható API-kat és webalkalmazásokat hozzanak létre. A TypeScript statikus gépeléssel bővíti az Expresst, javítva a kód karbantarthatóságát és korán elkapva a hibákat. A middleware függvények az Express sarokkövei, amelyek lehetővé teszik a kérések elfogását és feldolgozását, mielőtt azok elérnék az útvonal-kezelőket. Ez a cikk a fejlett TypeScript típusmintákat vizsgálja az Express middleware definiálásához és használatához, fokozva a típusbiztonságot és a kód áttekinthetőségét.
Az Express Middleware megértése
A middleware függvények olyan függvények, amelyek hozzáférnek a kérés objektumhoz (req), a válasz objektumhoz (res) és az alkalmazás kérés-válasz ciklusában lévő következő middleware függvényhez. A middleware függvények a következő feladatokat hajthatják végre:
- Bármilyen kód végrehajtása.
- Módosítások végrehajtása a kérés és a válasz objektumokon.
- A kérés-válasz ciklus befejezése.
- A következő middleware függvény meghívása a veremben.
A middleware függvények szekvenciálisan kerülnek végrehajtásra, ahogy hozzá vannak adva az Express alkalmazáshoz. A middleware gyakori felhasználási esetei a következők:
- Kérések naplózása.
- Felhasználók hitelesítése.
- Hozzáférés engedélyezése az erőforrásokhoz.
- Kérési adatok érvényesítése.
- Hibák kezelése.
Alap TypeScript Middleware
Egy alap TypeScript Express alkalmazásban egy middleware függvény így nézhet ki:
import { Request, Response, NextFunction } from 'express';
function loggerMiddleware(req: Request, res: Response, next: NextFunction) {
console.log(`Request: ${req.method} ${req.url}`);
next();
}
export default loggerMiddleware;
Ez az egyszerű middleware naplózza a kérés módszerét és URL-jét a konzolra. Bontsuk le a típusannotációkat:
Request: Az Express kérés objektumot képviseli.Response: Az Express válasz objektumot képviseli.NextFunction: Egy függvény, amely meghívásakor végrehajtja a következő middleware-t a veremben.
Ezt a middleware-t az Express alkalmazásban az alábbiak szerint használhatja:
import express from 'express';
import loggerMiddleware from './middleware/loggerMiddleware';
const app = express();
const port = 3000;
app.use(loggerMiddleware);
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
Fejlett típusminták a Middleware-hez
Bár az alap middleware példa működőképes, hiányzik belőle a rugalmasság és a típusbiztonság a bonyolultabb forgatókönyvekhez. Fedezzük fel a fejlett típusmintákat, amelyek javítják a middleware fejlesztést a TypeScript segítségével.
1. Egyéni kérés/válasz típusok
Gyakran előfordul, hogy ki kell bővítenie a Request vagy Response objektumokat egyéni tulajdonságokkal. Például a hitelesítés után érdemes hozzáadni egy user tulajdonságot a Request objektumhoz. A TypeScript lehetővé teszi a meglévő típusok kiegészítését deklarációs egyesítéssel.
// src/types/express/index.d.ts
import { Request as ExpressRequest } from 'express';
declare global {
namespace Express {
interface Request {
user?: {
id: string;
email: string;
// ... other user properties
};
}
}
}
export {}; // This is needed to make the file a module
Ebben a példában az Express.Request interfészt bővítjük ki egy opcionális user tulajdonság belefoglalásával. Most a hitelesítési middleware-ben feltöltheti ezt a tulajdonságot:
import { Request, Response, NextFunction } from 'express';
function authenticationMiddleware(req: Request, res: Response, next: NextFunction) {
// Simulate authentication logic
const userId = req.headers['x-user-id'] as string; // Or fetch from a token, etc.
if (userId) {
// In a real application, you would fetch the user from a database
req.user = {
id: userId,
email: `user${userId}@example.com`
};
next();
} else {
res.status(401).send('Unauthorized');
}
}
export default authenticationMiddleware;
És az útvonal-kezelőkben biztonságosan hozzáférhet a req.user tulajdonsághoz:
import express from 'express';
import authenticationMiddleware from './middleware/authenticationMiddleware';
const app = express();
const port = 3000;
app.use(authenticationMiddleware);
app.get('/profile', (req: Request, res: Response) => {
if (req.user) {
res.send(`Hello, ${req.user.email}! Your user ID is ${req.user.id}`);
} else {
// This should never happen if the middleware is working correctly
res.status(500).send('Internal Server Error');
}
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
2. Middleware gyárak
A middleware gyárak olyan függvények, amelyek middleware függvényeket adnak vissza. Ez a minta akkor hasznos, ha a middleware-t konkrét opciókkal vagy függőségekkel kell konfigurálnia. Például vegyünk egy naplózó middleware-t, amely üzeneteket naplóz egy adott fájlba:
import { Request, Response, NextFunction } from 'express';
import fs from 'fs';
import path from 'path';
function createLoggingMiddleware(logFilePath: string) {
return (req: Request, res: Response, next: NextFunction) => {
const logMessage = `[${new Date().toISOString()}] Request: ${req.method} ${req.url}\n`;
fs.appendFile(logFilePath, logMessage, (err) => {
if (err) {
console.error('Error writing to log file:', err);
}
next();
});
};
}
export default createLoggingMiddleware;
Ezt a middleware gyárat az alábbiak szerint használhatja:
import express from 'express';
import createLoggingMiddleware from './middleware/loggingMiddleware';
const app = express();
const port = 3000;
const logFilePath = path.join(__dirname, 'logs', 'requests.log');
app.use(createLoggingMiddleware(logFilePath));
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
3. Aszinkron Middleware
A Middleware függvényeknek gyakran kell aszinkron műveleteket végrehajtaniuk, például adatbázis-lekérdezéseket vagy API-hívásokat. Az aszinkron műveletek helyes kezeléséhez biztosítani kell, hogy a next függvény az aszinkron művelet befejezése után legyen meghívva. Ezt megteheti async/await vagy Promises használatával.
import { Request, Response, NextFunction } from 'express';
async function asyncMiddleware(req: Request, res: Response, next: NextFunction) {
try {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log('Asynchronous operation completed');
next();
} catch (error) {
next(error); // Pass the error to the error handling middleware
}
}
export default asyncMiddleware;
Fontos: Ne felejtse el kezelni a hibákat az aszinkron middleware-ben, és adja át azokat a hibakezelő middleware-nek a next(error) használatával. Ez biztosítja, hogy a hibák megfelelően legyenek kezelve és naplózva.
4. Hibakezelő Middleware
A hibakezelő middleware egy speciális típusú middleware, amely a kérés-válasz ciklus során előforduló hibákat kezeli. A hibakezelő middleware függvényeknek négy argumentumuk van: err, req, res és next.
import { Request, Response, NextFunction } from 'express';
function errorHandler(err: any, req: Request, res: Response, next: NextFunction) {
console.error(err.stack);
res.status(500).send('Something went wrong!');
}
export default errorHandler;
A hibakezelő middleware-t az összes többi middleware és útvonal-kezelő után kell regisztrálnia. Az Express a négy argumentum jelenléte alapján azonosítja a hibakezelő middleware-t.
import express from 'express';
import asyncMiddleware from './middleware/asyncMiddleware';
import errorHandler from './middleware/errorHandler';
const app = express();
const port = 3000;
app.use(asyncMiddleware);
app.get('/', (req, res) => {
throw new Error('Simulated error!'); // Simulate an error
});
app.use(errorHandler); // Error handling middleware MUST be registered last
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
5. Kérés validáló Middleware
A kérés validálása a biztonságos és megbízható API-k építésének kritikus szempontja. A Middleware használható a bejövő kérési adatok érvényesítésére, és annak biztosítására, hogy azok megfeleljenek bizonyos kritériumoknak, mielőtt azok elérnék az útvonal-kezelőket. A joi vagy az express-validator könyvtárak használhatók a kérések validálására.
Íme egy példa az express-validator használatával:
import { Request, Response, NextFunction } from 'express';
import { body, validationResult } from 'express-validator';
const validateCreateUserRequest = [
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }),
(req: Request, res: Response, next: NextFunction) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
];
export default validateCreateUserRequest;
Ez a middleware validálja az email és password mezőket a kérés törzsében. Ha a validálás sikertelen, akkor egy 400 Bad Request választ ad vissza a hibaüzenetek tömbjével. Ezt a middleware-t az útvonal-kezelőkben az alábbiak szerint használhatja:
import express from 'express';
import validateCreateUserRequest from './middleware/validateCreateUserRequest';
const app = express();
const port = 3000;
app.post('/users', validateCreateUserRequest, (req, res) => {
// If validation passes, create the user
res.send('User created successfully!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
6. Függőségi injekció a Middleware-hez
Ha a middleware függvények külső szolgáltatásoktól vagy konfigurációktól függenek, a függőségi injekció segíthet javítani a tesztelhetőséget és a karbantarthatóságot. Használhat egy függőségi injekciós konténert, mint például a tsyringe, vagy egyszerűen átadhatja a függőségeket argumentumként a middleware gyáraknak.
Íme egy példa egy middleware gyárra függőségi injekcióval:
// src/services/UserService.ts
export class UserService {
async createUser(email: string, password: string): Promise {
// In a real application, you would save the user to a database
console.log(`Creating user with email: ${email} and password: ${password}`);
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate a database operation
}
}
// src/middleware/createUserMiddleware.ts
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/UserService';
function createCreateUserMiddleware(userService: UserService) {
return async (req: Request, res: Response, next: NextFunction) => {
try {
const { email, password } = req.body;
await userService.createUser(email, password);
res.status(201).send('User created successfully!');
} catch (error) {
next(error);
}
};
}
export default createCreateUserMiddleware;
// src/app.ts
import express from 'express';
import createCreateUserMiddleware from './middleware/createUserMiddleware';
import { UserService } from './services/UserService';
import errorHandler from './middleware/errorHandler';
const app = express();
const port = 3000;
app.use(express.json()); // Parse JSON request bodies
const userService = new UserService();
const createUserMiddleware = createCreateUserMiddleware(userService);
app.post('/users', createUserMiddleware);
app.use(errorHandler);
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
Gyakorlati tanácsok a TypeScript Middleware-hez
- Tartsa a middleware függvényeket kicsinek és fókuszáltnak. Minden middleware függvénynek egyetlen felelőssége legyen.
- Használjon leíró neveket a middleware függvényekhez. A névnek egyértelműen jeleznie kell, hogy mit csinál a middleware.
- Kezelje megfelelően a hibákat. Mindig fogja el a hibákat, és adja át azokat a hibakezelő middleware-nek a
next(error)használatával. - Használjon egyéni kérés/válasz típusokat a típusbiztonság növeléséhez. Szükség szerint bővítse a
RequestésResponseinterfészeket egyéni tulajdonságokkal. - Használjon middleware gyárakat a middleware konfigurálásához konkrét opciókkal.
- Dokumentálja a middleware függvényeit. Magyarázza el, hogy mit csinál a middleware és hogyan kell használni.
- Tesztelje alaposan a middleware függvényeit. Írjon egységteszteket annak biztosítására, hogy a middleware függvények megfelelően működnek.